package com.zige.zige.view.panoplayer.glwrapper;

import android.opengl.GLES30;
import android.util.Log;

/**
 * Created by admin on 16/1/5.
 */
public class GlProgram {

    private static final String TAG = "GlProgram";

    public enum VertexAttributeLocation
    {
        POSITION (0),
        NORMAL (1),
        TANGENT (2),
        BINORMAL (3),
        COLOR (4),
        UV0 (5),
        UV1 (6),
        JOINT_INDICES (7),
        JOINT_WEIGHTS (8),
        FONT_PARMS (9);

        private final int location;

        VertexAttributeLocation(int location) {
            this.location = location;
        }

        public int toInt() {
            return this.location;
        }
    }

    private int program = -1;
    private int vertexShader = -1;
    private int fragmentShader = -1;
    private int uMvp = -1;
    private int uModel = -1;
    private int uView = -1;
    private int uProjection = -1;
    private int uColor = -1;
    private int uFadeDirection = -1;
    private int uTexm = -1;
    private int uTexm2 = -1;
    private int uJoints = -1;
    private int uColorTableOffset = -1;
    private int uClipUVs = -1;

    public GlProgram(String vertexSrc, String fragmentSrc) {
        vertexShader = GLES30.glCreateShader(GLES30.GL_VERTEX_SHADER);
        if (!this.compileShader(vertexShader, vertexSrc)) {
            Log.e(TAG, "Failed to compile vertex shader");
        }

        fragmentShader = GLES30.glCreateShader(GLES30.GL_FRAGMENT_SHADER);
        if (!this.compileShader(fragmentShader, fragmentSrc)) {
            Log.e(TAG, "Failed to compile fragment shader");
        }

        program = GLES30.glCreateProgram();
        GLES30.glAttachShader(program, vertexShader);
        GLES30.glAttachShader(program, fragmentShader);

        // set attributes before linking
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.POSITION.toInt(), "Position");
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.NORMAL.toInt(), "Normal");
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.TANGENT.toInt(), "Tangent");
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.BINORMAL.toInt(), "Binormal");
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.COLOR.toInt(), "VertexColor");
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.UV0.toInt(), "TexCoord");
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.UV1.toInt(), "TexCoord1");
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.JOINT_INDICES.toInt(), "JointIndices");
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.JOINT_WEIGHTS.toInt(), "JointWeights");
        GLES30.glBindAttribLocation(program, VertexAttributeLocation.FONT_PARMS.toInt(), "FontParms");

        // link and error check
        GLES30.glLinkProgram(program);
        int[] r = new int[1];
        GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, r, 0);
        if (r[0] == GLES30.GL_FALSE)
        {
            Log.e(TAG, "Linking program failed: " + GLES30.glGetProgramInfoLog(program));
        }
        uMvp = GLES30.glGetUniformLocation(program, "Mvpm" );
        uModel = GLES30.glGetUniformLocation(program, "Modelm");
        uView = GLES30.glGetUniformLocation(program, "Viewm");
        uProjection = GLES30.glGetUniformLocation(program, "Projectionm");
        uColor = GLES30.glGetUniformLocation(program, "UniformColor");
        uFadeDirection = GLES30.glGetUniformLocation(program, "UniformFadeDirection");
        uTexm = GLES30.glGetUniformLocation(program, "Texm");
        uTexm2 = GLES30.glGetUniformLocation(program, "Texm2");
        uJoints = GLES30.glGetUniformLocation(program, "Joints");
        uColorTableOffset = GLES30.glGetUniformLocation(program, "ColorTableOffset");
        uClipUVs = GLES30.glGetUniformLocation(program, "ClipUVs");

        GLES30.glUseProgram(program);

        // texture and image_external bindings
        for ( int i = 0; i < 8; i++ )
        {
            String name = "Texture" + i;
            int uTex = GLES30.glGetUniformLocation(program, name);
            if ( uTex != -1 )
            {
                GLES30.glUniform1i(uTex, i);
            }
        }

        GLES30.glUseProgram(0);
    }

    public int getProgram() {
        return program;
    }

    public int getVertexShader() {
        return vertexShader;
    }

    public int getFragmentShader() {
        return fragmentShader;
    }

    public int getuMvp() {
        return uMvp;
    }

    public int getuModel() {
        return uModel;
    }

    public int getuView() {
        return uView;
    }

    public int getuProjection() {
        return uProjection;
    }

    public int getuColor() {
        return uColor;
    }

    public int getuFadeDirection() {
        return uFadeDirection;
    }

    public int getuTexm() {
        return uTexm;
    }

    public int getuTexm2() {
        return uTexm2;
    }

    public int getuJoints() {
        return uJoints;
    }

    public int getuColorTableOffset() {
        return uColorTableOffset;
    }

    public int getuClipUVs() {
        return uClipUVs;
    }

    public void cleanUp() {

    }

    private boolean compileShader(int shader, String src) {
        GLES30.glShaderSource(shader, src);
        GLES30.glCompileShader(shader);

        int[] r = new int[1];
        GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, r, 0);
        if ( r[0] == GLES30.GL_FALSE )
        {
            Log.e(TAG, GLES30.glGetShaderInfoLog(shader));
            GLES30.glDeleteShader(shader);
            return false;
        }
        return true;
    }
}
